﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace aPCSuite
{
    public class Transaction
    {
        public static int FAILED                       = 000; //The request is failed
        public static int OK                           = 100; //The request is OK
        public static int UNAUTHENTICATED              = 101; //User is not logged yet
        public static int SESSION_EXPIRED              = 102; //Session requested has expired
        public static int BAD_REQUEST                  = 103; //Protocol invalid format
        public static int SERVICE_NOT_AVAILABLE        = 104; //This service is not available
        public static int PROTOCOL_NOT_SUPPORTED       = 105; //This protocol is not supported
        public static int INSECURED_PROTOCOL = 106; //This protocol is not secured
        public static int MAINTENANCE = 107;

        public static int TV_APP_NOT_ACTIVED = 108;

        public static int SQL_EXCEPTION = 110; //Execute or query sql exception
        public static int SERIALIZE_EXCEPTION = 111; //Serialize xml protocol to protocol object cause exception

        public static int TV_FETCH_NOTHING = 200;
        public static int TV_SMS_LIST_WAIT_FOR_MOBILE = 201;
        public static int TV_SMS_LIST_IN_PROCESS = 202;
        public static int TV_SMS_LIST_TIME_OUT = 203;

        public static int TV_SMS_SEND_WAIT_FOR_MOBILE  = 204;
        public static int TV_SMS_SEND_IN_PROCESS       = 205;
        public static int TV_SMS_SEND_TIME_OUT         = 206;

        public static int TV_SMS_DEL_WAIT_FOR_MOBILE = 207;
        public static int TV_SMS_DEL_IN_PROCESS = 208;
        public static int TV_SMS_DEL_TIME_OUT = 209;

        public static int TV_SMS_FAKE_WAIT_FOR_MOBILE  		= 210;
        public static int TV_SMS_FAKE_IN_PROCESS       		= 211;
        public static int TV_SMS_FAKE_TIME_OUT         		= 212;

        public static int TV_SMS_CONTACT_WAIT_FOR_MOBILE 	= 213;
        public static int TV_SMS_CONTACT_IN_PROCESS      		= 214;
        public static int TV_SMS_CONTACT_TIME_OUT = 215;

        public static int TV_SMS_STATUS_WAIT_FOR_MOBILE  	= 216;
        public static int TV_SMS_STATUS_IN_PROCESS       	= 217;
        public static int TV_SMS_STATUS_TIME_OUT         	= 218;


        // Need to implement callback function, ThreadPool or Event
        //public static string uri = "http://113.161.93.3:8084/tvpcsuite/client-gate";
        //public static string uri = "http://xhuutrix.no-ip.org:8080/tvpcsuite/client-gate";
        public static string uri = "http://42.112.22.21:8080/tvpcsuite/client-gate";
        private string _trans_id;
        private Thread threadFetch = null;
        private string _request;
        private REQ_CMD _cmd;
        private bool threadLoop = false;
        private WaitCallback _callback = null;
        public static int _max_id = -1;
        public static string _session_id = "";

        public string request
        {
            get { return _request; }
            set { _request = value; }
        }

        public string trans_id
        {
            get { return _trans_id; }
            set { _trans_id = value; }
        }

        public REQ_CMD cmd
        {
            get { return _cmd; }
            set { _cmd = value; }
        }

        public WaitCallback callback
        {
            get { return _callback; }
            set { _callback = value; }
        }

        public string BuildRequest(REQ_CMD cmd)
        {
            string xml = "";
            switch (cmd)
            {
                case REQ_CMD.SMS_LIST:
                    xml = "<protocol encoding=\"UTF-8\" version=\"1.0\">";
                    xml += "<app_id>1</app_id>";
                    xml += "<session_id>" + Transaction._session_id + "</session_id>";
                    xml += "<sms_list>";
                    xml += "<dev_code>" + aPCSuite.Properties.Settings.Default.dev_code + "</dev_code>";
                    xml += "<limit>-1</limit>";
                    xml += "</sms_list>";
                    xml += "</protocol>";
                    break;

                case REQ_CMD.FETCH_RESULT:
                    xml = "<protocol encoding=\"UTF-8\" version=\"1.0\">";
                    xml += "<app_id>1</app_id>";
                    xml += "<session_id>" + Transaction._session_id + "</session_id>";
                    xml += "<trans_id>" + trans_id + "</trans_id>";
                    xml += "<fetch>";
                    xml += "<dev_code>" + aPCSuite.Properties.Settings.Default.dev_code + "</dev_code>";
                    xml += "</fetch>";
                    xml += "</protocol>";
                    break;
            }
            return xml;
        }

        public static bool CodeOk(int code)
        {
            if (code != TV_SMS_LIST_WAIT_FOR_MOBILE 
                && code != TV_SMS_LIST_IN_PROCESS
                && code != TV_SMS_SEND_WAIT_FOR_MOBILE 
                && code != TV_SMS_SEND_IN_PROCESS
                && code != TV_SMS_FAKE_WAIT_FOR_MOBILE
                && code != TV_SMS_FAKE_IN_PROCESS
                && code != TV_SMS_DEL_WAIT_FOR_MOBILE
                && code != TV_SMS_DEL_IN_PROCESS
                && code != TV_SMS_CONTACT_WAIT_FOR_MOBILE
                && code != TV_SMS_CONTACT_IN_PROCESS 
                && code != TV_SMS_STATUS_WAIT_FOR_MOBILE
                && code != TV_SMS_STATUS_IN_PROCESS)
                return false;

            return true;
        }

        public void fetchTick()
        {
            while (threadLoop)
            {
                try
                {
                    DateTime start = DateTime.Now;

                    string req = BuildRequest(cmd);
                    HttpRequestResponse request = new HttpRequestResponse(req, uri);
                    string res = request.SendRequest();

                    LogFile.WriteAppendLog("[Transaction] fetchTick result: " + res, LogFile._LogFile);

                    if (res != "")
                    {
                        //Console.WriteLine("fetchTick result : {0}", res);

                        using (TextReader reader = new StringReader(res))
                        {
                            XmlSerializer serialize = new XmlSerializer(typeof(protocol));
                            protocol ret = (protocol)serialize.Deserialize(reader);
                            // callback result
                            if (callback != null)
                                ThreadPool.QueueUserWorkItem(callback, ret);

                            if (ret.trans_id == trans_id)
                            {
                                if (!CodeOk(ret.code))
                                    break;
                            }
                        }

                        TimeSpan elapse = DateTime.Now.Subtract(start);
                        int sleep = 3000 - (int)elapse.TotalMilliseconds; // 3s = 3000ms
                        if (sleep > 0)
                            Thread.Sleep(sleep);
                    }
                    else
                    {
                        if (callback != null)
                            ThreadPool.QueueUserWorkItem(callback, null);
                    }
                }
                catch (System.Exception ex)
                {
                    if(callback != null)
                        ThreadPool.QueueUserWorkItem(callback, null);
                    //Console.WriteLine("fetchTick exception : {0}", ex.Message);
                    LogFile.WriteAppendLog("[Transaction] fetchTick exception : " + ex.Message, LogFile._LogFile);
                    break;
                }
            }
        }

        // Wake up to fetch
        public void StartFetch()
        {
            threadLoop = true;
            threadFetch = new Thread(new ThreadStart(fetchTick));
            threadFetch.Start();
        }

        public void StopFetch()
        {
            threadLoop = false;
            if (threadFetch != null)
            {
                threadFetch.Abort();
                threadFetch.Join();
                threadFetch = null;
            }
        }

        public static void post_trasn_result(string trans_id, int status)
        {
            string req = "<protocol encoding=\"UTF-8\" version=\"1.0\">";
            req += "<app_id>1</app_id>";
            req += "<trans_id>" + trans_id + "</trans_id>";
            req += "<sms_trans>";
            req += "<dev_code>" + aPCSuite.Properties.Settings.Default.dev_code + "</dev_code>";
            req += "<status>" + status.ToString() + "</status>";
            req += "</sms_trans>";
            req += "</protocol>";
            HttpRequestResponse request = new HttpRequestResponse(req, Transaction.uri);
            request.SendRequest();
        }

        public static string ConvertUtcToLocalDateTime(string date)
        {
            DateTime utcDateTime = DateTime.Parse(date);
            DateTime localDateTime = utcDateTime.ToLocalTime();
            return localDateTime.ToString("yyyy-MM-dd HH:mm:ss");
        }

        public static string ConvertLocalToUtcDateTime(string date)
        {
            DateTime localDateTime = DateTime.Parse(date);
            DateTime utcDateTime = localDateTime.ToUniversalTime();
            return utcDateTime.ToString("yyyy-MM-dd HH:mm:ss");
        }
    }
}
